package com.Core;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import android.app.Activity;
import android.os.DropBoxManager.Entry;
import android.service.wallpaper.WallpaperService.Engine;
import android.widget.TextView;

import com.DataWrapper.EventTracker;
import com.Object.ObjType;
import com.Object.SeaObject;
import com.Object.AllRoute.Shell;
import com.Triocean.R;

public class GameLogic {
	private int scaleSlop = 0, transSlop = 0;
	public int transPhase = 0;
	private EventTracker tracker = GameEngine.tracker;
	private boolean aniMark = false;
	int[] X_cor = { 0, -1, 0, 1 };
	int[] Y_cor = { -1, 0, 1, 0 };

	public void CheckAniForCurPos() {
		if (aniMark) {
			if (!GameEngine.disableInput) {
				scaleSlop = (scaleSlop + 1) % GameAnimation.scaleSlop;
				if (scaleSlop == 0)
					GameAnimation.NextRatio();
			} else {
				if (GameEngine.mapModel.Get(GameEngine.tracker.curX,
						GameEngine.tracker.curY).getType() == ObjType.Shell) {
					Shell shell = (Shell) GameEngine.mapModel.Get(
							GameEngine.tracker.curX, GameEngine.tracker.curY);
					shell.SwapHoldingObj();
					if (GameEngine.curObj.getType() != ObjType.Null) {
						RemoveAniMark();
						GameEngine.disableInput = false;
						// ko random va giu nguyen con tro cur
					} else {
						RemakeField();
						RemoveAniMark();
						GameEngine.disableInput = false;
						GameEngine.curObj = SeaObject.CreateObject(SeaObject
								.randomObject());
					}
				} else {

					if ((GameEngine.curObj.getType() != ObjType.Tornado && GameEngine.mapModel
							.Get(GameEngine.tracker.curX,
									GameEngine.tracker.curY).getType() != ObjType.Null)
							|| (GameEngine.curObj.getType() == ObjType.Tornado && GameEngine.mapModel
									.Get(GameEngine.tracker.curX,
											GameEngine.tracker.curY).getType() == ObjType.Null)) {

						RemoveAniMark();
						GameEngine.disableInput = false;
						// ko random va giu nguyen con tro cur
					} else {
						transSlop = (transSlop + 1) % GameAnimation.transSlop;
						if (transSlop == 0)
							transPhase++;
						if (transPhase == GameAnimation.transPhases + 1
								|| (GameEngine.curObj.getType() != ObjType.Tornado && GameEngine.mapModel
										.Get(GameEngine.tracker.curX,
												GameEngine.tracker.curY)
										.getType() == ObjType.Null)
								|| (GameEngine.curObj.getType() == ObjType.Tornado && GameEngine.mapModel
										.Get(GameEngine.tracker.curX,
												GameEngine.tracker.curY)
										.getType() != ObjType.Null)) {
							transPhase = 0;
							UpdateProfile();
							RemakeField();
							RemoveAniMark();
							GameEngine.disableInput = false;
						}
						GameEngine.mainGameAct.runOnUiThread(new Runnable() {
							public void run() {
								GameEngine.mainGameAct.UpdateInfo();
							}
						});
						GameEngine.curObj = SeaObject.CreateObject(SeaObject
								.randomObject());
					}
				}
			}
		}
	}

	public void SetAniMark() {
		GameEngine.mergedObj = null;
		GameEngine.stepScore = 0;
		aniMark = true;
		if (GameEngine.mapModel.Get(GameEngine.tracker.curX,
				GameEngine.tracker.curY).getType() != ObjType.Shell) {
			if (GameEngine.curObj.getType() == ObjType.Pearl) {
				pearl();
			} else if (GameEngine.curObj.getType() == ObjType.Rock) {
				GameEngine.mergedObj = GameEngine.curObj;
			} else if (GameEngine.curObj.getType() == ObjType.Tornado) {
				tornado();
			} else if (GameEngine.curObj.getType() == ObjType.GhostShip) {
				GameEngine.mergedObj = GameEngine.curObj;
			} else if (GameEngine.curObj.getType() == ObjType.Ship) {
				GameEngine.mergedObj = GameEngine.curObj;
			} else {
				chain(GameEngine.curObj, GameEngine.tracker.curX,
						GameEngine.tracker.curY);
			}
		}
	}

	private void tornado() {
		// TODO Auto-generated method stub
		if (GameEngine.mapModel.Get(GameEngine.tracker.curX,
				GameEngine.tracker.curY).getType() == ObjType.GhostShip) {
			GameEngine.mergedObj = SeaObject.CreateObject(ObjType.TreasureMap);
			chain(SeaObject.CreateObject(ObjType.TreasureMap),
					GameEngine.tracker.curX, GameEngine.tracker.curY);
		} else {
			GameEngine.mergedObj = SeaObject.CreateObject(ObjType.Null);
		}
	}

	private void chain(SeaObject curObj, int curX, int curY) {
		// TODO Auto-generated method stub
		int x, y;
		List<Integer> markList = new ArrayList<Integer>();
		Map.Entry<SeaObject, Integer> curEntry = operate(markList, curObj,
				curX, curY);
		if (curEntry == null) {
			GameEngine.stepScore += curObj.getScore();
			GameEngine.mergedObj = curObj;
		} else {
			GameEngine.stepScore += (curObj.getScore() + curEntry.getValue());
			GameEngine.mergedObj = curEntry.getKey();
			for (int l : markList) {
				x = (l - 1) / GameEngine.MAP_SIZE;
				y = (l - 1) % GameEngine.MAP_SIZE;
				GameEngine.mapModel.Get(x, y).SetScaleAni();
			}
		}
	}

	private void pearl() {
		// TODO Auto-generated method stub
		int x, y;
		SeaObject apearObj = null;
		int score = 0;
		List<Integer> markListFinal = null;
		for (int i = 0; i < 4; i++) {
			x = GameEngine.tracker.curX + X_cor[i];
			y = GameEngine.tracker.curY + Y_cor[i];
			if (x > -1 && x < GameEngine.MAP_SIZE && y > -1
					&& y < GameEngine.MAP_SIZE) {
				ObjType tempObjType = change(x, y);
				if (tempObjType != null) {
					List<Integer> markList = new ArrayList<Integer>();
					SeaObject tempObj = SeaObject.CreateObject(tempObjType);
					Map.Entry<SeaObject, Integer> curEntry = operate(markList,
							tempObj, GameEngine.tracker.curX,
							GameEngine.tracker.curY);
					if (curEntry != null) {
						if (score < curEntry.getValue() + tempObj.getScore()) {
							score = curEntry.getValue() + tempObj.getScore();
							apearObj = curEntry.getKey();
							markListFinal = markList;
						}
					}
				}
			}
		}
		if (apearObj == null) {
			GameEngine.mergedObj = SeaObject.CreateObject(ObjType.Rock);
		} else {
			GameEngine.stepScore += score;
			GameEngine.mergedObj = apearObj;
			for (int l : markListFinal) {
				x = (l - 1) / GameEngine.MAP_SIZE;
				y = (l - 1) % GameEngine.MAP_SIZE;
				GameEngine.mapModel.Get(x, y).SetScaleAni();
			}
		}
	}

	private ObjType change(int x, int y) {
		// TODO Auto-generated method stub
		if (GameEngine.mapModel.Get(x, y).getType() != ObjType.Null
				&& GameEngine.mapModel.Get(x, y).getType() != ObjType.Rock
				&& GameEngine.mapModel.Get(x, y).getType() != ObjType.Ship
				&& GameEngine.mapModel.Get(x, y).getType() != ObjType.GhostShip)
			return GameEngine.mapModel.Get(x, y).getType();
		else
			return null;
	}

	private Map.Entry<SeaObject, Integer> operate(List<Integer> markList,
			SeaObject tempObj, int xTempObj, int yTempObt) {
		// TODO Auto-generated method stub
		int x, y, xx, yy;
		int num = 0;
		List<Integer> tempMark = new ArrayList<Integer>();
		for (int i = 0; i < 4; i++) {
			x = xTempObj + X_cor[i];
			y = yTempObt + Y_cor[i];
			if (x > -1 && x < GameEngine.MAP_SIZE && y > -1
					&& y < GameEngine.MAP_SIZE) {
				if (GameEngine.mapModel.Get(x, y).getType() == tempObj
						.getType()) {
					num++;
					tempMark.add(oneDimension(x, y));
					for (int j = 0; j < 4; j++) {
						xx = x + X_cor[j];
						yy = y + Y_cor[j];
						if (xx > -1 && xx < GameEngine.MAP_SIZE && yy > -1
								&& yy < GameEngine.MAP_SIZE) {
							if (!(xx == xTempObj && yy == yTempObt)
									&& GameEngine.mapModel.Get(xx, yy)
											.getType() == tempObj.getType()) {
								num++;
								tempMark.add(oneDimension(xx, yy));
							}
						}
					}
				}
			}

		}

		if (num > 1 && tempObj.getParent() != null) {
			SeaObject newObj = SeaObject.CreateObject(tempObj.getParent());
			int score = caculateScore(num, newObj);
			for (Integer t : tempMark) {
				markList.add(t);
			}
			Map.Entry<SeaObject, Integer> newEntry = operate(markList, newObj,
					xTempObj, yTempObt);
			if (newEntry != null) {
				newEntry.setValue(newEntry.getValue() + score);
				return newEntry;
			} else {
				return new MyEntry<SeaObject, Integer>(newObj, score);
			}
		} else {
			return null;
		}
	}

	private int caculateScore(int num, SeaObject newObj) {
		// TODO Auto-generated method stub
		int newscore = newObj.getScore();
		if (num > 2)
			newscore *= 2;
		return newscore;
	}

	private Integer oneDimension(int x, int y) {
		// TODO Auto-generated method stub
		return x * GameEngine.MAP_SIZE + y + 1;
	}

	public void RemoveAniMark() {
		aniMark = false;
		for (int i = 0; i < GameEngine.MAP_SIZE; i++)
			for (int j = 0; j < GameEngine.MAP_SIZE; j++)
				GameEngine.mapModel.Get(i, j).RemoveScaleAni();
		GameAnimation.ResetScaleRatio();
		tracker.SetTaboo();
	}

	private void RemakeField() {
		if (GameEngine.curObj.getType() == ObjType.Tornado) {
			if (GameEngine.mapModel.Get(GameEngine.tracker.curX,
					GameEngine.tracker.curY).getType() == ObjType.GhostShip)
				GameEngine.ghostShipMap.remove(GameEngine.mapModel.Get(
						GameEngine.tracker.curX, GameEngine.tracker.curY));
		}

		for (int i = 0; i < GameEngine.MAP_SIZE; i++) {
			for (int j = 0; j < GameEngine.MAP_SIZE; j++) {
				if (GameEngine.mapModel.Get(i, j).isScaleAni()) {
					GameEngine.mapModel.Set(i, j, ObjType.Null);
					GameEngine.mapModel.Get(i, j).RemoveScaleAni();
				}
			}
		}
		if (GameEngine.mergedObj != null
				&& GameEngine.mapModel.Get(GameEngine.tracker.curX,
						GameEngine.tracker.curY).getType() != ObjType.Shell) {

			GameEngine.mapModel.Set(GameEngine.tracker.curX,
					GameEngine.tracker.curY, GameEngine.mergedObj.getType());
			if (GameEngine.mergedObj.getType() == ObjType.Poseidon)
				GameEngine.mainGameAct.finish(); // qua man
		}
		GameEngine.mergedObj = null;
		if (gameOver() == true)
			GameEngine.mainGameAct.HandleEndGame(1);
		
		handleShip();

		GameEngine.profile.addScore(GameEngine.stepScore);

		if (GameEngine.profile.getScore() >= GameEngine.curMap.getPointGoal())
			GameEngine.mainGameAct.HandleEndGame(0);

		GameEngine.stepScore = 0;
	}

	private boolean gameOver() {
		// TODO Auto-generated method stub
		boolean over = true;
		for (int i = 0; i < GameEngine.MAP_SIZE; i++)
			for (int j = 0; j < GameEngine.MAP_SIZE; j++) {
				if (GameEngine.mapModel.Get(i, j).getType() == ObjType.Null)
					over = false;
			}
		return over;
	}

	private void handleShip() {
		// TODO Auto-generated method stub
		if (GameEngine.curObj.getType() == ObjType.GhostShip) {
			GameEngine.ghostShipMap.put(
					GameEngine.mapModel.Get(GameEngine.tracker.curX,
							GameEngine.tracker.curY),
					oneDimension(GameEngine.tracker.curX,
							GameEngine.tracker.curY));
		} else if (GameEngine.curObj.getType() == ObjType.Ship) {
			GameEngine.shipCount++;
			GameEngine.shipPrior.put(GameEngine.mapModel.Get(
					GameEngine.tracker.curX, GameEngine.tracker.curY),
					GameEngine.shipCount);
		}
		toggleGhostShip();
		killShip();

		changeShipPosition();
	}

	private void changeShipPosition() {
		// TODO Auto-generated method stub
		Random ran = new Random();
		List<SeaObject> list = new ArrayList<SeaObject>();
		List<Integer> listvt = new ArrayList<Integer>();
		SeaObject temp;
		int tempvt;
		for (int i = 0; i < GameEngine.MAP_SIZE; i++) {
			for (int j = 0; j < GameEngine.MAP_SIZE; j++) {
				if (GameEngine.mapModel.Get(i, j).getType() == ObjType.Ship) {
					list.add(GameEngine.mapModel.Get(i, j));
					listvt.add(oneDimension(i, j));
				}
			}
		}
		if (list.size() != 0) {
			for (int i = 0; i < list.size(); i++)
				for (int j = i + 1; j < list.size(); j++)
					if (GameEngine.shipPrior.get(list.get(i)) > GameEngine.shipPrior
							.get(list.get(j))) {
						temp = list.get(i);
						list.set(i, list.get(j));
						list.set(j, temp);
						tempvt = listvt.get(i);
						listvt.set(i, listvt.get(j));
						listvt.set(j, tempvt);
					}
			int x, y;
			for (int i = 0; i < list.size(); i++) {
				int vtx = xDimension(listvt.get(i));
				int vty = yDimension(listvt.get(i));
				List<Integer> vtden = new ArrayList<Integer>();
				for (int k = 0; k < 4; k++) {
					x = vtx + X_cor[k];
					y = vty + Y_cor[k];
					if (x > -1
							&& x < GameEngine.MAP_SIZE
							&& y > -1
							&& y < GameEngine.MAP_SIZE
							&& GameEngine.mapModel.Get(x, y).getType() == ObjType.Null) {
						vtden.add(oneDimension(x, y));
					}
				}
				if (vtden.size() != 0) {
					int newvt = vtden.get(ran.nextInt(vtden.size()));
					GameEngine.mapModel.Swap(vtx, vty, xDimension(newvt),
							yDimension(newvt));
				}
			}
		}
	}

	private void toggleGhostShip() {
		// TODO Auto-generated method stub
		Set<SeaObject> set = GameEngine.ghostShipMap.keySet();
		Random ran = new Random();
		if (set != null) {// if ton tai ghostship
			for (SeaObject seaObject : set) {
				int x = xDimension(GameEngine.ghostShipMap.get(seaObject));
				int y = yDimension(GameEngine.ghostShipMap.get(seaObject));
				List<Integer> l = new ArrayList<Integer>();
				for (int i = 0; i < GameEngine.MAP_SIZE; i++) {
					for (int j = 0; j < GameEngine.MAP_SIZE; j++) {
						if (GameEngine.mapModel.Get(i, j).getType() == ObjType.Null)
							l.add(oneDimension(i, j));
					}
				}
				if (l != null) {
					// GameEngine.mapModel.Set(x, y, ObjType.Null);
					int vl = l.get(ran.nextInt(l.size()));
					GameEngine.ghostShipMap.put(seaObject, vl);
					GameEngine.mapModel.Swap(x, y, xDimension(vl),
							yDimension(vl));
					// GameEngine.mapModel.Set(xDimension(vl), yDimension(vl),
					// ObjType.GhostShip);
				}
			}
		}
	}

	private void killShip() {
		// TODO Auto-generated method stub
		int x, y;
		boolean[][] dd = new boolean[GameEngine.MAP_SIZE][GameEngine.MAP_SIZE];
		for (int i = 0; i < GameEngine.MAP_SIZE; i++)
			for (int j = 0; j < GameEngine.MAP_SIZE; j++) {
				dd[i][j] = false;
			}

		for (int i = 0; i < GameEngine.MAP_SIZE; i++)
			for (int j = 0; j < GameEngine.MAP_SIZE; j++) {
				if (GameEngine.mapModel.Get(i, j).getType() == ObjType.Ship
						&& dd[i][j] == false) {
					LinkedList<Integer> q = new LinkedList<Integer>();
					LinkedList<Integer> willKill = new LinkedList<Integer>();
					boolean exit = false;
					q.add(oneDimension(i, j));
					while (!q.isEmpty()) {
						int head = q.remove();
						willKill.add(head);
						dd[i][j] = true;
						for (int t = 0; t < 4; t++) {
							x = xDimension(head) + X_cor[t];
							y = yDimension(head) + Y_cor[t];
							if (x > -1 && x < GameEngine.MAP_SIZE && y > -1
									&& y < GameEngine.MAP_SIZE
									&& dd[x][y] == false) {
								dd[x][y] = true;
								if (x == GameEngine.tracker.curX
										&& y == GameEngine.tracker.curY) {
									if (GameEngine.curObj.getType() == ObjType.Ship) {
										q.add(oneDimension(x, y));
									}
								} else {
									if (GameEngine.mapModel.Get(x, y).getType() == ObjType.Ship) {
										q.add(oneDimension(x, y));
									} else if (GameEngine.mapModel.Get(x, y)
											.getType() == ObjType.Null
											|| GameEngine.mapModel.Get(x, y)
													.getType() == ObjType.GhostShip) {
										exit = true;
										dd[x][y] = false;
									}
								}
							}
						}
					}
					if (!exit) { // ton tai vung ship bi dong
						int vtMaxPrior = 0;
						int maxPrior = 0;
						for (Integer vt : willKill) {
							int temp = GameEngine.shipPrior
									.get(GameEngine.mapModel.Get(
											xDimension(vt), yDimension(vt)));
							if (maxPrior < temp) {
								maxPrior = temp;
								vtMaxPrior = vt;
							}
						}
						if (willKill.size() > 2) {
							// bien tau thanh null bien tau cuoi thanh ban do
							// kho bau
							for (Integer vt : willKill) {
								GameEngine.mapModel.Set(xDimension(vt),
										yDimension(vt), ObjType.Null);
							}
							GameEngine.mapModel
									.Set(xDimension(vtMaxPrior),
											yDimension(vtMaxPrior),
											ObjType.TreasureMap);
							// GameEngine.stepScore +=
							// (GameEngine.TREASURE_MAP_SCORE);
						} else {// bien tau thanh tau chim
							for (Integer vt : willKill) {
								GameEngine.mapModel.Set(xDimension(vt),
										yDimension(vt), ObjType.Shipwreck);
							}
						}
						// xet vi tri ban do kho bau vua thu vao hoac con tau
						// chim cuoi cung
						chain(GameEngine.mapModel.Get(xDimension(vtMaxPrior),
								yDimension(vtMaxPrior)),
								xDimension(vtMaxPrior), yDimension(vtMaxPrior));
						// ghep vung 3 tau chim hoac 3 ban do ngay lap tuc de
						// mergedObj cho vung tau khac nua
						for (int i1 = 0; i1 < GameEngine.MAP_SIZE; i1++) {
							for (int j1 = 0; j1 < GameEngine.MAP_SIZE; j1++) {
								if (GameEngine.mapModel.Get(i1, j1)
										.isScaleAni()) {
									GameEngine.mapModel.Set(i1, j1,
											ObjType.Null);
									GameEngine.mapModel.Get(i1, j1)
											.RemoveScaleAni();
								}
							}
						}
						if (GameEngine.mergedObj != null)
							GameEngine.mapModel.Set(xDimension(vtMaxPrior),
									yDimension(vtMaxPrior),
									GameEngine.mergedObj.getType());
						GameEngine.mergedObj = null;
					}
				}

			}
	}

	private int yDimension(int l) {
		// TODO Auto-generated method stub
		return (l - 1) % GameEngine.MAP_SIZE;
	}

	private int xDimension(int l) {
		// TODO Auto-generated method stub
		return (l - 1) / GameEngine.MAP_SIZE;
	}

	private void UpdateProfile() {
	}
}

class MyEntry<K, V> implements Map.Entry<K, V> {
	private final K key;
	private V value;

	public MyEntry(K key, V value) {
		this.key = key;
		this.value = value;
	}

	@Override
	public K getKey() {
		return key;
	}

	@Override
	public V getValue() {
		return value;
	}

	@Override
	public V setValue(V value) {
		V old = this.value;
		this.value = value;
		return old;
	}
}
